﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Physic = StillDesign.PhysX; //PhysX
using PhysicMath = StillDesign.PhysX.MathPrimitives; //PhysX

namespace Game
{
    public class PhysicActorDescription
    {
        public Physic.ActorDescription ActorDescription = new Physic.ActorDescription();
        public Physic.BodyDescription BodyDescription = null;

        public IDK.SceneNode SceneNode
        {
            get;
            set;
        }

        public PhysicActorDescription(IDK.SceneNode node)
        {
            SceneNode = node;
            ActorDescription.SetToDefault();
            ActorDescription.Name = node.GetName();
        }

        protected void CreateBody(float density = 1, float mass = 0)
        {
            BodyDescription = new Physic.BodyDescription();
            //link body
            ActorDescription.Density = density;
            ActorDescription.BodyDescription = BodyDescription;
        }

        public void DisableCollision()
        {
            ActorDescription.Flags |= Physic.ActorFlag.DisableCollision;
        }

        protected void SetKinematic()
        {
            BodyDescription.BodyFlags |= Physic.BodyFlag.Kinematic;
        }

        protected void AddShape(Physic.ShapeDescription shape)
        {
            ActorDescription.Shapes.Add(shape);
        }

        public PhysicScene.SceneObjectGroupID GroupID
        {
            set
            {
                ActorDescription.Group = (short)value;
            }
        }

        protected Physic.ShapeDescription AddShapeAABBBox(IDK.AABBox aabbox)
        {
            //IDK.AABBox aabbox = new IDK.AABBox(new IDK.Vector3(2, 2, 2), new IDK.Vector3(-1, -1, -1));
            var shape = new Physic.BoxShapeDescription(aabbox.Width, aabbox.Height, aabbox.Depth);

            var center = IDK.Vector3.Lerp(aabbox.Min, aabbox.Max, 0.5f); // get center
            shape.LocalPosition = IDKToPhysic.ToVector3(center);

            AddShape(shape);

            return shape;
        }

        public IDK.Vector3 Position
        {
            get
            {
                return new IDK.Vector3(ActorDescription.GlobalPose.M41, ActorDescription.GlobalPose.M42, ActorDescription.GlobalPose.M43);
            }
            set
            {
                ActorDescription.GlobalPose = PhysicMath.Matrix.Translation(IDKToPhysic.ToVector3(value));
            }
        }

        public IDK.Quaternion Orientation
        {
            set
            {
                var dirMatrix = PhysicMath.Matrix.RotationQuaternion(IDKToPhysic.ToQuaternion(value));

                ActorDescription.GlobalPose = PhysicMath.Matrix.Multiply(dirMatrix, ActorDescription.GlobalPose);
            }
        }

        public void AddTriggerShape()
        {
            var transform = SceneNode.GetTransformation();
            var aabbox = SceneNode.GetTransformation().GetOriginalAABBox();

            AddTriggerShape(aabbox.Width, aabbox.Height, aabbox.Depth, SceneNode.GetName(), new IDK.Vector3(0, 1, 0));
        }

        public void AddTriggerShape(float width, float height, float depth, String triggerName, IDK.Vector3 localPosition)
        {
            //Shape
            Physic.BoxShapeDescription shape = new Physic.BoxShapeDescription(width, height, depth);
            shape.Name = triggerName;
            shape.Flags |= Physic.ShapeFlag.TriggerEnable;
            shape.LocalPosition = IDKToPhysic.ToVector3(localPosition);
            AddShape(shape);
        }
    }

    public class PhysicStaticBoxDescription : PhysicActorDescription
    {
        public PhysicStaticBoxDescription(IDK.SceneNode node)
            : base(node)
        {
            CreateBody();

            GroupID = PhysicScene.SceneObjectGroupID.Static;

            SetKinematic();


            var transform = SceneNode.GetTransformation();
            var aabbox = transform.GetOriginalAABBox();
            AddShapeAABBBox(aabbox);
            Position = transform.GetWorldPosition();
        }
    }

    public class PhysicDummyBoxDescription : PhysicActorDescription
    {
        public PhysicDummyBoxDescription(IDK.SceneNode node)
            : base(node)
        {
            CreateBody();

            GroupID = PhysicScene.SceneObjectGroupID.Static;

            SetKinematic();

            var transform = SceneNode.GetTransformation();
            var aabbox = transform.GetOriginalAABBox();

            AddShapeAABBBox(aabbox).Flags |= Physic.ShapeFlag.DisableCollision;
            Position = transform.GetWorldPosition();
        }
    }

    public class PhysicDynamicBoxDescription : PhysicActorDescription
    {
        public PhysicDynamicBoxDescription(IDK.SceneNode node)
            : base(node)
        {
            CreateBody();

            GroupID = PhysicScene.SceneObjectGroupID.Dynamic;

            //calculate offset
            //var center = aabbox.Max - aabbox.Min;
            //var offset = transform.GetWorldPosition() - 

            var transform = SceneNode.GetTransformation();
            var aabbox = transform.GetOriginalAABBox();
            AddShapeAABBBox(aabbox);
            Position = transform.GetWorldPosition();
            Orientation = transform.GetWorldOrientation();
        }
    }
}
